#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file is for get the mapping relationship of subsystem_name/component_name
# and their directory. The code is from Yude Chen.

import logging
import copy
import os
import logging
from abc import ABC, abstractmethod
from collections import defaultdict
from typing import Text, List, Dict, AnyStr, DefaultDict
from pprint import pprint
import preprocess
from pkgs.gn_common_tool import GnVariableParser
from pkgs.simple_yaml_tool import SimpleYamlTool
from pkgs.basic_tool import BasicTool


_config = SimpleYamlTool.read_yaml("config.yaml")

def extension_handler(paragraph: Text):
    return GnVariableParser.string_parser("output_extension", paragraph).strip('"')


def hap_name_handler(paragraph: Text):
    return GnVariableParser.string_parser("hap_name", paragraph).strip('"')


def target_type_handler(paragraph: Text):
    tt = GnVariableParser.string_parser("target_type", paragraph).strip('"')
    return tt


def mod_handler(paragraph: Text):
    return GnVariableParser.string_parser("mode", paragraph).strip('"')


def gn_lineno_collect(match_pattern: str, project_path: str) -> DefaultDict[str, List[int]]:
    """
    在整个项目路径下搜索有特定target类型的BUILD.gn
    :param match_pattern: 进行grep的pattern，支持扩展的正则
    :param project_path: 项目路径（搜索路径）
    :return: {gn_file: [line_no_1, line_no_2, ..]}
    """
    black_list = _config.get("black_list")
    tbl = [x for x in black_list if os.sep in x]

    def handler(content: Text) -> List[str]:
        t = list(filter(lambda y: len(y) > 0, list(
            map(lambda x: x.strip(), content.split("\n")))))
        for item in tbl:
            p = os.path.join(project_path, item)
            t = list(filter(lambda x: p not in x, t))
        return t

    grep_list = BasicTool.grep_ern(match_pattern, path=project_path,
                                   include="BUILD.gn", exclude=tuple(black_list), post_handler=handler)
    gn_line_dict: DefaultDict[str, List[int]] = defaultdict(list)
    for gl in grep_list:
        gn_file, line_no, _ = gl.split(":")
        gn_line_dict[gn_file].append(line_no)
    return gn_line_dict


class TargetNameParser:
    @classmethod
    def single_parser(cls, paragraph: Text) -> str:
        """
        查找类似shared_library("xxx")这种括号内只有一个参数的target的名称
        :param paragraph: 要解析的段落
        :return: target名称，如果是变量，不会对其进行解析
        """
        return BasicTool.re_group_1(paragraph, r"\w+\((.*)\)")

    @classmethod
    def second_parser(cls, paragraph: Text) -> str:
        """
        查找类似target("shared_library","xxx")这种的target名称（括号内第二个参数）
        :param paragraph: 要解析的段落
        :return: target名称，如果是变量，不会的其进行解析
        """
        return BasicTool.re_group_1(paragraph, r"\w+\(.*?, *(.*?)\)")



class BasePostHandler(ABC):
    def __call__(self, unit: Dict[str, AnyStr]) -> str:
        return self.run(unit)
    
    @abstractmethod
    def run(self, unit: Dict[str, AnyStr]) -> str:
        ...


def add_prefix(content: str, prefix: str) -> str:
    if content and (not content.startswith(prefix)):
        return prefix+content
    return content


def add_postfix(content: str, postfix: str) -> str:
    if content and (not content.endswith(postfix)):
        return content+postfix
    return content


class DefaultPostHandler(BasePostHandler):
    def run(self, unit: Dict[str, AnyStr]):
        if "extension" in unit.keys() and (not unit["output_name"].endswith(unit["extension"])):
            out = unit["output_name"].rstrip(
                ".")+"."+unit["extension"].lstrip(".")
            return out
        return unit["output_name"]


class UnittestPostHandler(BasePostHandler):
    def run(self, unit: Dict[str, AnyStr]):
        if "output_extension" in unit.keys() and (not unit["output_name"].endswith(unit["output_extension"])):
            out = unit["output_name"].rstrip(
                ".")+"."+unit["output_extension"].lstrip(".")
            return out
        return unit["output_name"]


class HapPackPostHandler(BasePostHandler):
    def run(self, unit: Dict[str, AnyStr]):
        hap_name = unit.get("hap_name")
        mode = unit.get("mode")
        return hap_name + "." + mode


class HAPPostHandler(BasePostHandler):
    """
    for ohos_hap
    """

    def run(self, unit: Dict[str, AnyStr]):
        extension = _config.get("default_extension").get("app")
        gn_hap_name = unit.get("hap_name")
        if gn_hap_name:
            return add_postfix(gn_hap_name, extension)
        return unit["output_name"]+extension


class SOPostHandler(BasePostHandler):
    """
    for shared_library
    """

    def run(self, unit: Dict[str, AnyStr]):
        output_name = unit["output_name"]
        prefix = _config.get("default_prefix").get("shared_library")
        if unit.get("extension"):
            extension = unit.get("extension")
        else:
            extension = _config.get("default_extension").get("shared_library")
        if not extension.startswith('.'):
            extension = '.'+extension
        output_name = add_postfix(output_name, extension)
        return add_prefix(output_name, prefix)


class APostHandler(BasePostHandler):
    """
    for static library
    """

    def run(self, unit: Dict[str, AnyStr]):
        output_name = unit["output_name"]
        prefix = _config.get("default_prefix").get("static_library")
        extension: str = _config.get("default_extension").get("static_library")
        if not extension.startswith('.'):
            extension = '.'+extension
        output_name = add_postfix(output_name, extension)
        return add_prefix(output_name, prefix)


class LiteLibPostHandler(BasePostHandler):
    """
    for lite_library
    """

    def run(self, unit: Dict[str, AnyStr]):
        tp = unit["real_target_type"]
        output_name = unit["output_name"]
        if tp == "static_library":
            prefix = _config.get("default_prefix").get("static_library")
            extension = _config.get("default_extension").get("static_library")
        elif tp == "shared_library":
            prefix = _config.get("default_prefix").get("shared_library")
            extension = _config.get("default_extension").get("shared_library")
        else:
            prefix = str()
            extension = str()
        if extension and (not extension.startswith('.')):
            extension = '.'+extension
        output_name = add_postfix(output_name, extension)
        return add_prefix(output_name, prefix)


class LiteComponentPostHandler(BasePostHandler):
    """
    for lite_component
    """

    def run(self, unit: Dict[str, AnyStr]):
        tp = unit["real_target_type"]
        output_name = unit["output_name"]
        extension = unit.get("output_extension")
        if tp == "shared_library":
            prefix = _config.get("default_prefix").get("shared_library")
            extension = _config.get("default_extension").get("shared_library")
        else:
            if tp != "executable":
                unit["description"] = "virtual node"
            prefix = str()
            extension = str()
        if extension and (not extension.startswith('.')):
            extension = '.'+extension
        output_name = add_postfix(output_name, extension)
        return add_prefix(output_name, prefix)


class TargetPostHandler(BasePostHandler):
    """
    for target(a,b){}
    """

    def run(self, unit: Dict[str, AnyStr]):
        ...


def lite_lib_s2m_post_handler(unit: Dict, result_dict: Dict) -> None:
    rt = unit.get("real_target_type")
    new_unit = copy.deepcopy(unit)
    if rt == "shared_library":
        new_unit["real_target_type"] = "static_library"
        k = LiteLibPostHandler()(new_unit)
        new_unit["description"] = "may not exist"
        result_dict["lite_library"][k] = new_unit
    elif rt == "static_library":
        new_unit["real_target_type"] = "shared_library"
        k = LiteLibPostHandler()(new_unit)
        new_unit["description"] = "may not exist"
        result_dict["lite_library"][k] = new_unit
    else:
        new_unit["real_target_type"] = "shared_library"
        k = LiteLibPostHandler()(new_unit)
        new_unit["description"] = "may not exist"
        result_dict["lite_library"][k] = new_unit

        new_new_unit = copy.deepcopy(unit)
        new_new_unit["real_target_type"] = "static_library"
        k = LiteLibPostHandler()(new_new_unit)
        new_new_unit["description"] = "may not exist"
        result_dict["lite_library"][k] = new_new_unit


def target_s2m_post_handler(unit: Dict, result_dict: Dict) -> None:
    unit["description"] = "may not exist"
    tmp_a = copy.deepcopy(unit)
    tmp_a["real_target_type"] = "static_library"
    k = LiteLibPostHandler()(tmp_a)
    result_dict["target"][k] = tmp_a

    tmp_s = copy.deepcopy(unit)
    tmp_s["real_target_type"] = "shared_library"
    k = LiteLibPostHandler()(tmp_s)
    result_dict["target"][k] = tmp_s